-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
Fix events remove listener emission #60137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #60137 +/- ##
==========================================
- Coverage 88.55% 88.53% -0.02%
==========================================
Files 704 704
Lines 208087 208088 +1
Branches 40019 40014 -5
==========================================
- Hits 184266 184233 -33
- Misses 15818 15862 +44
+ Partials 8003 7993 -10
🚀 New features to boost your workflow:
|
Adds test coverage for the removeListener event being emitted when a once() listener is automatically removed after execution. This verifies that streams and other EventEmitters correctly emit removeListener events when once() wrappers clean up.
When the last listener is removed and _eventsCount becomes 0, the removeListener event was not being emitted because the check was inside the else block. This moves the removeListener emission outside the conditional to ensure it always fires when a listener is removed.
074f626 to
d322e4d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could delete 2 more lines:
del 690-691, 715-716
+718 if (events.removeListener !== undefined)
+719 this.emit('removeListener', type, listener);
Delete lines 690-691, 715-716, and add consolidated emit at 718-719. The Problem I Found When I tried this, the test failed because:
Current State I kept both emit calls inside their respective branches:
Your consolidation proposal cannot work due to the early return at line |
|
Sorry if I am wrong. And I think is same as |
@simonkcleung Thank you for the suggestion! I explored consolidating the emit calls, but found a issue: Edge Case Problem: Test case (line 42-48): ee.on('hello', listener1);
ee.on('removeListener', common.mustNotCall());
ee.removeListener('hello', listener2); // listener2 never added - should NOT emit
Performance:
Consolidation would require a tracking variable (let removed or let removedListener), adding overhead to every removeListener() call.
The current approach with duplicate emit calls is actually optimal:
- Zero overhead (no extra variables)
- Handles edge cases correctly
- Properly handles wrapped listeners (list.listener || listener vs listener)
I've kept the duplicate emits while fixing the original bug. Thanks for the detailed review! |
You are right. |
Description
This PR fixes a bug where the
removeListenerevent was not being emitted when the last listener was removed from an EventEmitter.Background
When
removeListener()is called and the last listener is removed (_eventsCount === 0), the code path that emits theremoveListenereventwas being skipped. This was because the emission logic was inside the
elseblock of the event count check.This issue particularly affects
once()listeners, which automatically callremoveListener()after execution. If the once listener was thelast listener, the
removeListenerevent would not fire.Changes
removeListenerevent emission outside the conditional block to ensure it always executes when a listener isremoved
once()listeners withremoveListenerevent monitoringTest Plan
Related Issues
fixes: #59977